#include <memory>
#include <string>
#include "InnerType.h"
#include "XnccServer.h"
#include "XnccType.h"
#include "flat_hash_map"

namespace xncc {
namespace foundation {
    class EventLoop;
    class XnccAddress;
    class DatagramAcceptChannel;
    class DatagramSocketChannel;
    class SubDatagramServer;
    class UdpSocket;
    class DatagramServer final : public XnccServer
    {
      public:
        DatagramServer(EventLoop*                   loop,
                       std::shared_ptr<XnccAddress> listenAddr,
                       std::string                  nameArg,
                       const std::set<std::string>& blacklist = {});
        ~DatagramServer() override;

        DatagramServer(const DatagramServer&)             = delete;
        DatagramServer(const DatagramServer&&)            = delete;
        DatagramServer& operator=(const DatagramServer&)  = delete;
        DatagramServer& operator=(const DatagramServer&&) = delete;

        void               init() override;
        void               start() override;
        [[nodiscard]] auto Type() const -> shared::XNCC_SERVER_TYPE override { return shared::XNCC_SERVER_TYPE::DGRAM; }

      private:
        void handleIoMsg(const char* msg, uint32_t len, types::thread_id_t tid, types::connection_id_t connId);

        void newConnection(int sockfd, types::connection_id_t connId, std::shared_ptr<XnccAddress> peerAddr);

        void createSubServer();
        void handleNewConnection(int sockfd, types::connection_id_t connId, std::shared_ptr<XnccAddress> peerAddr);
        void removeConnection(types::connection_id_t connId, const std::string& disconnectedReason);

        EventLoop*                                                                         loop_;  // the acceptor loop
        const std::string                                                                  ipPort_;
        const std::string                                                                  name_;
        std::shared_ptr<DatagramAcceptChannel>                                             serverChannel_;
        std::shared_ptr<UdpSocket>                                                         serverSocket_;
        ska::flat_hash_map<types::connection_id_t, std::shared_ptr<DatagramSocketChannel>> clientChs_;
        std::vector<std::shared_ptr<SubDatagramServer>>                                    subServers_;
        size_t                                                                             nextSubserverIndex_ = 0;
    };
}  // namespace foundation
}  // namespace xncc